package com.wanfajie.smsdistribute.util

import net.sourceforge.pinyin4j.PinyinHelper
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType
import java.util.*
import kotlin.collections.HashMap
import kotlin.reflect.KProperty

val SIMPLE_PINYIN_FORMAT = HanyuPinyinOutputFormat().apply {
    caseType = HanyuPinyinCaseType.UPPERCASE
    toneType = HanyuPinyinToneType.WITHOUT_TONE
    vCharType = HanyuPinyinVCharType.WITH_V
}

fun toPinyin(str: String, separator: String = "", process: ((Any) -> Any)? = null): String {
    val result = str.map {
        val pinyinStr = PinyinHelper.toHanyuPinyinStringArray(it, SIMPLE_PINYIN_FORMAT)?.get(0)
        val value = pinyinStr ?: it
        process?.invoke(value) ?: value
    }

    return result.joinToString(separator = separator)
}

fun toPinyinInitial(str: String): String {
    return toPinyin(str) {
        if (it is String) {
            it[0]
        } else {
            it
        }
    }
}

private fun asciiCharRemap(ch: Char): Char {
    return when (ch.toInt()) {
        // 数字
        in 48..57 -> ch - 48
        // 大写字母
        in 65..90 -> ch - 55
        // 小写字母
        in 97..122 -> ch - 61
        // 可打印符号
        in 32..47 -> ch + 30
        in 58..64 -> ch + 20
        in 91..96 -> ch - 6
        in 123..127 -> ch - 32
        // 控制字符
        in 0..31 -> ch + 96
        // 超出部分不映射
        else -> ch
    }
}

class HanYuComparator(
        var asc: Boolean = true,
        var byPinyin: Boolean = true
): Comparator<String> {

    companion object {
        val DEFAULT = HanYuComparator()
    }

    override fun compare(o1: String, o2: String): Int {
        val pinyin1: String
        val pinyin2: String
        if (byPinyin) {
            pinyin1 = o1.pinyinInitial
            pinyin2 = o2.pinyinInitial
        } else {
            pinyin1 = o1
            pinyin2 = o2
        }

        var i = 0
        while (i < o1.length && i < o2.length) {
            val ch1 = asciiCharRemap(pinyin1[i])
            val ch2 = asciiCharRemap(pinyin2[i])
            var result = if (asc)
                ch1 - ch2
            else
                ch2 - ch1

            // 拼音首字母相同就直接对比字符Unicode值, 保证中文字相同的在一起
            if (result == 0) {
                result = if (asc)
                    o1[i] - o2[i]
                else
                    o2[i] - o1[i]
            }

            if (result != 0) {
                return result
            }

            i++
        }

        return when {
            o1.length == o2.length -> 0
            o1.length > o2.length -> 1
            else -> -1
        }
    }
}

val String.pinyinInitial: String by object {

    private val mCache: MutableMap<String, String> = HashMap()

    operator fun getValue(obj: String, prop: KProperty<*>): String {
        return getCachePinyinInitial(obj)
    }

    @Synchronized
    private fun getCachePinyinInitial(str: String): String {
        var value = mCache[str]

        if (value == null) {
            value = toPinyinInitial(str)
            if (value.isEmpty()) value = " "
            mCache[str] = value
        }

        return value
    }
}
